-- DungeonPuzzleM
-- Created by huangr Sep/20/2016
-- 冒险系装备

module("DungeonPuzzleM", package.seeall);

local PUZZLE_GROUP_ID = 34;
local GAIN_BUFF_ATTRIB = "dlc_puzzle_gained";

local PuzzleTable = {};
local DungeonPuzzle = {};
local PuzzleGainWay = {};

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    -- 转换下department信息表
    local dungeon_puzzle_CSV = get_dungeon_puzzle_CSV();
    for i = 1, #dungeon_puzzle_CSV do
        PuzzleTable[dungeon_puzzle_CSV[i].id] = dungeon_puzzle_CSV[i];

        local areaId = dungeon_puzzle_CSV[i].dungeon_area;
        if DungeonPuzzle[areaId] == nil then
            DungeonPuzzle[areaId] = {};
        end

        table.insert(DungeonPuzzle[areaId], dungeon_puzzle_CSV[i].id);

        -- 根据分类存下
        if PuzzleGainWay[areaId] == nil then
            PuzzleGainWay[areaId] = {};
        end

        local gainWay = dungeon_puzzle_CSV[i].gain_way;
        if PuzzleGainWay[areaId][gainWay] == nil then
            PuzzleGainWay[areaId][gainWay] = {};
        end

        table.insert(PuzzleGainWay[areaId][gainWay], dungeon_puzzle_CSV[i].id);
    end


    dungeon_puzzle_CSV = {};
end

-- 模块初始化
function init()
    loadCsv();

    EventMgr.removeAll("DungeonPuzzleM");
    -- 关注奖励事件
    EventMgr.register("DungeonPuzzleM", event.DO_BONUS, whenDoBonus);
    EventMgr.register("DungeonPuzzleM", event.ITEM_COUNT_UPDATED, whenItemUpdate);
end

-- 尝试记录已经获得
function tryMarkHasGained(classId)
    if type(classId) ~= "number" then
        return;
    end

    -- 必须大于0
    if ItemM.query(classId, "group") == PUZZLE_GROUP_ID and ItemM.getAmount(ME.user, classId) > 0 then

        local index = query(classId, "gain_buff_index");

        if 1 ~= BuffDataM.query(GAIN_BUFF_ATTRIB, index) then
            BuffDataM.set(GAIN_BUFF_ATTRIB, index, 1);
        end

        if DungeonM.isPause() or not DungeonM.isInDungeon() then
            ItemM.updateItem(ME.user, classId, 0);
        end
    end
end

-- 天空探索中是服务端直接奖励的，所以需要关注下物品数量变化
function whenItemUpdate(classId)
    tryMarkHasGained(classId);
end

-- 物品奖励
function whenDoBonus(bonus)
    if bonus[1] ~= 1 then
        -- 不是物品，不处理
        return;
    end

    tryMarkHasGained(bonus[2]);
end

-- 检索信息
function query(id, path)
    local m = PuzzleTable[id];

    if not m or not path then
        return m;
    end

    return m[path];
end

-- 检查是否所有的地图都集齐了
function isHaveAllPuzzle(areaId)
    local arr = DungeonPuzzle[areaId];

    if type(arr) ~= "table" then
        return false;
    end

    -- 其中一个没有，那么就没有
    for _, id in pairs(arr) do
        if not isHaveThisPuzzle(id) then
            return false;
        end

    end

    return true;
end

-- 检查是否显示(捡到其中一个拼图就可以显示)
function hasOne(areaId)

    local arr = DungeonPuzzle[areaId];

    if type(arr) ~= "table" then
        return false;
    end

    for _, id in pairs(arr) do
        if isHaveThisPuzzle(id) then
            return true;
        end
    end

    return false;
end

-- 当前收集到的拼图在UI
function getPuzzleList(areaId)
    local arr = DungeonPuzzle[areaId];

    if type(arr) ~= "table" then
        return false;
    end

    local ret = {};

    for _, id in pairs(arr) do
        if isHaveThisPuzzle(id) then
            table.insert(ret, id);
        end
    end

    return ret;
end

-- 是否拼图迷宫
function isPuzzleDungeon(dungeonId)
    if DungeonPuzzle[dungeonId] ~= nil then
        return true;
    end

    return false;
end

-- 获得对应迷宫的所有拼图
function getAreaPuzzle(areaId)
    return DungeonPuzzle[areaId];
end

-- 检查某类拼图是否开放
function checkAreaPuzzleIsOpen(areaId)
    -- 前置关卡是否解锁
    return FormulaM.invoke("CALC_PRE_PUZZLE_DUNGEON_IS_UNLOCK", areaId);
end

-- 通过区域类型和获取方式获得对应拼图
function getPuzzleByGainWay(areaId, way)
    local wayList = PuzzleGainWay[areaId] or {};

    return wayList[way];
end

-- 计算神龙许愿的收藏品的奖励
function calcCollectionPuzzle()
    local allAreas = table.keys(PuzzleGainWay);

    local allPuzzles = {};
    for _, areaId in pairs(allAreas) do
        -- 如果获得同类型中的一个
        if FormulaM.invoke("CHECK_COLLECTION_PUZZLE_BONUS", areaId) then
            local puzzles = PuzzleGainWay[areaId]["want_collection"] or {};

            allPuzzles = table.append(allPuzzles, puzzles);
        end
    end

    -- 当前没有的才能获得
    local canGetPuzzles = {};
    for _, id in pairs(allPuzzles) do
        if not isHaveThisPuzzle(id) then
            table.insert(canGetPuzzles, id);
        end
    end

    return canGetPuzzles;
end

-- 神龙许愿的想要收藏品（比较特殊）
function getWantCollectionPuzzle()
    local canGetPuzzles = calcCollectionPuzzle();
    local count = #canGetPuzzles;

    if count < 1 then
        return nil;
    elseif count == 1 then
        return canGetPuzzles[1];
    end

    local function  sortItem(item1, item2)
        return item1 < item2;
    end

    -- 为了与服务端一样需要排序下
    table.sort(canGetPuzzles, sortItem);

    local seed = DungeonM.getRandSeed("DRAGON_WISH_PUZZLE");

    return canGetPuzzles[seed%count + 1];
end

-- 是否是迷宫拼图
function isPuzzleItem(classId)
    if PUZZLE_GROUP_ID == ItemM.query(classId, "group") then
        return true;
    end

    return false;
end

-- 检查是否播放合成拼图的光效
function checkPlayDlcPuzzleEffect(dungeonId)
    local index = FormulaM.invoke("CALC_DLC_PUZZLE_REMIND_INDEX", dungeonId);

    if index == nil then
        return false;
    end

    if BuffDataM.query("dlc_puzzle_remind", index) == 1 then
        return false;
    end

    return true;
end

-- 标记拼图合成光效已提醒
function markAsReminded(areaId)
    local index = FormulaM.invoke("CALC_DLC_PUZZLE_REMIND_INDEX", areaId);

    if index == nil then
        return;
    end

    BuffDataM.set("dlc_puzzle_remind", index, 1);

    -- 通知服务器该功能已经提醒过
    Operation.cmd_dlc_puzzle_remind(areaId, "complete");
end

-- 检查当前应该播放光效的拼图
function checkSinglePuzzlePlay(id)
    local remindIndex = query(id, "effect_index");

    if isHaveThisPuzzle(id) and BuffDataM.query("single_puzzle_remind", remindIndex) ~= 1 then
        return true;
    end

    return false;
end

-- 记录播放过了
function markCurPuzzleReminded(id)
    local remindIndex = query(id, "effect_index");

    if remindIndex == nil then
        return;
    end

    BuffDataM.set("single_puzzle_remind", remindIndex, 1);

    -- 通知服务器该功能已经提醒过
    Operation.cmd_dlc_puzzle_remind(id, "single_puzzle");
end

-- 更新被关闭的拼图信息
function updateClosedDlc(data)
    ME.user.dbase:set("close_puzzle_dlc", data);
end

-- 当前迷宫是否被关闭
function curDlcPuzzleIsOpen(areaId)
    local data = ME.user.dbase:query("close_puzzle_dlc", {});

    if table.indexOf(data, areaId) ~= -1 then
        return false;
    end

    return true;
end

-- 如果当前迷宫未开放则当前奖励无效
function isInValidPuzzle(puzzleBonus)
    if puzzleBonus[1] == 1 then
        local areaId = query(puzzleBonus[2], "dungeon_area");

        if not curDlcPuzzleIsOpen(areaId) then
            return true;
        end
    end

    return false;
end

-- 判断是否已经拥有过了某一个拼图
function isHaveThisPuzzle(classId)
    local groupId = ItemM.query(classId, "group");
    if groupId == PUZZLE_GROUP_ID then
        local index = query(classId, "gain_buff_index");

        if 1 == BuffDataM.query(GAIN_BUFF_ATTRIB, index) then
            return true;
        end
    end

    return false;
end

-- 同一类型的奖励是否已经全部获得
function isHasAllBySameWay(areaId, gainWay)
    local areaPuzzles = PuzzleGainWay[areaId] or {};
    local puzzles = areaPuzzles[gainWay] or {};
    for _, id in pairs(puzzles) do
        if not isHaveThisPuzzle(id) then
            return false;
        end
    end

    return true;
end